Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-289.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 94881 objects.
Mean distance to the closest unit in the map: 1.172.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_mes.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt           tmax      
 Length:94881       Length:94881       Min.   : 1.000   Min.   :-53.0  
 Class :character   Class :character   1st Qu.: 4.000   1st Qu.:148.0  
 Mode  :character   Mode  :character   Median : 6.000   Median :198.0  
                                       Mean   : 6.497   Mean   :200.2  
                                       3rd Qu.: 9.000   3rd Qu.:255.0  
                                       Max.   :12.000   Max.   :403.0  
      tmin             precip           nevada           prof_nieve      
 Min.   :-121.00   Min.   :  0.00   Min.   :0.000000   Min.   :   0.000  
 1st Qu.:  53.00   1st Qu.:  3.00   1st Qu.:0.000000   1st Qu.:   0.000  
 Median :  98.00   Median : 10.00   Median :0.000000   Median :   0.000  
 Mean   :  98.86   Mean   : 16.25   Mean   :0.000295   Mean   :   0.467  
 3rd Qu.: 148.00   3rd Qu.: 22.00   3rd Qu.:0.000000   3rd Qu.:   0.000  
 Max.   : 254.00   Max.   :422.00   Max.   :6.000000   Max.   :1834.000  
    longitud        latitud            altitud      
 Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:38.28   1st Qu.: -5.6417   1st Qu.:  42.0  
 Median :40.82   Median : -3.4500   Median : 247.0  
 Mean   :39.66   Mean   : -3.4350   Mean   : 418.5  
 3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 656.0  
 Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
5079 6817 5120 2530  630 5674 2239 3219 2480 2846 5115 4799 4408 3598    2 6316 
  17   18   19   20   21   22   23   24   25 
5326 6861 7044   10 6047 7460   64    8 1189 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("tmax", "tmin", "precip", "nevada", "prof_nieve", "longitud", "latitud", "altitud")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
           tmax       tmin     precip      nevada prof_nieve  longitud
[1,] -0.7648887 -0.7582582  0.6200670 0.020915288 0.03149500 0.4479989
[2,]  0.3432055  0.1640591 -0.2969694 0.004657616 0.03215826 0.1393199
         latitud   altitud
[1,]  0.14844188 0.4728733
[2,] -0.01755875 0.3996106

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
  longitud     nevada    altitud    latitud       tmax       tmin prof_nieve 
 0.9495866  0.9409413  0.9277203  0.9196942  0.9179936  0.9136398  0.9131914 
    precip 
 0.8689148 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.:148.0   1st Qu.:  53.00   1st Qu.:  3.00  
 Median : 6.000   Median :198.0   Median :  98.00   Median : 10.00  
 Mean   : 6.497   Mean   :200.2   Mean   :  98.87   Mean   : 16.25  
 3rd Qu.: 9.000   3rd Qu.:255.0   3rd Qu.: 148.00   3rd Qu.: 22.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.00   Max.   :422.00  
     nevada            prof_nieve          longitud        latitud        
 Min.   :0.0000000   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0.0000000   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.: -5.6417  
 Median :0.0000000   Median :  0.0000   Median :40.82   Median : -3.4500  
 Mean   :0.0001897   Mean   :  0.3714   Mean   :39.66   Mean   : -3.4350  
 3rd Qu.:0.0000000   3rd Qu.:  0.0000   3rd Qu.:42.08   3rd Qu.:  0.4914  
 Max.   :3.0000000   Max.   :709.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 418.4  
 3rd Qu.: 656.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.:148.0   1st Qu.:  53.00   1st Qu.:  3.00  
 Median : 6.000   Median :198.0   Median :  98.00   Median : 10.00  
 Mean   : 6.497   Mean   :200.2   Mean   :  98.88   Mean   : 16.25  
 3rd Qu.: 9.000   3rd Qu.:255.0   3rd Qu.: 148.00   3rd Qu.: 22.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.00   Max.   :422.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.: -5.6417  
 Median :0   Median :  0.0000   Median :40.82   Median : -3.4500  
 Mean   :0   Mean   :  0.3714   Mean   :39.66   Mean   : -3.4351  
 3rd Qu.:0   3rd Qu.:  0.0000   3rd Qu.:42.08   3rd Qu.:  0.4914  
 Max.   :0   Max.   :709.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 418.4  
 3rd Qu.: 656.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt         tmax             tmin            precip     
 Min.   : 1.0   Min.   : 69.00   Min.   :-24.00   Min.   : 3.00  
 1st Qu.: 2.0   1st Qu.: 86.25   1st Qu.:-12.50   1st Qu.: 6.00  
 Median : 7.0   Median : 92.00   Median :  6.50   Median :10.50  
 Mean   : 6.8   Mean   : 96.80   Mean   :  7.90   Mean   :11.40  
 3rd Qu.:12.0   3rd Qu.: 96.75   3rd Qu.: 29.25   3rd Qu.:14.75  
 Max.   :12.0   Max.   :140.00   Max.   : 35.00   Max.   :24.00  
     nevada       prof_nieve     longitud        latitud          altitud     
 Min.   :1.00   Min.   :0.0   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.:1.25   1st Qu.:0.0   1st Qu.:40.48   1st Qu.:-3.450   1st Qu.:263.0  
 Median :2.00   Median :0.5   Median :41.08   Median :-2.242   Median :435.6  
 Mean   :1.80   Mean   :1.1   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:2.00   3rd Qu.:1.0   3rd Qu.:41.67   3rd Qu.:-1.033   3rd Qu.:608.1  
 Max.   :3.00   Max.   :7.0   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 4.000   1st Qu.:149.0   1st Qu.:  53.00   1st Qu.:  3.00  
 Median : 6.000   Median :198.0   Median :  98.00   Median : 10.00  
 Mean   : 6.499   Mean   :200.3   Mean   :  98.96   Mean   : 16.22  
 3rd Qu.: 9.000   3rd Qu.:255.0   3rd Qu.: 148.00   3rd Qu.: 22.00  
 Max.   :12.000   Max.   :403.0   Max.   : 254.00   Max.   :422.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889  
 1st Qu.:0   1st Qu.:  0.0000   1st Qu.:38.28   1st Qu.: -5.6417  
 Median :0   Median :  0.0000   Median :40.82   Median : -3.4500  
 Mean   :0   Mean   :  0.1427   Mean   :39.66   Mean   : -3.4347  
 3rd Qu.:0   3rd Qu.:  0.0000   3rd Qu.:42.08   3rd Qu.:  0.4914  
 Max.   :0   Max.   :165.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  42.0  
 Median : 247.0  
 Mean   : 417.4  
 3rd Qu.: 656.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt         tmax             tmin            precip     
 Min.   : 1.0   Min.   : 69.00   Min.   :-24.00   Min.   : 3.00  
 1st Qu.: 2.0   1st Qu.: 86.25   1st Qu.:-12.50   1st Qu.: 6.00  
 Median : 7.0   Median : 92.00   Median :  6.50   Median :10.50  
 Mean   : 6.8   Mean   : 96.80   Mean   :  7.90   Mean   :11.40  
 3rd Qu.:12.0   3rd Qu.: 96.75   3rd Qu.: 29.25   3rd Qu.:14.75  
 Max.   :12.0   Max.   :140.00   Max.   : 35.00   Max.   :24.00  
     nevada       prof_nieve     longitud        latitud          altitud     
 Min.   :1.00   Min.   :0.0   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.:1.25   1st Qu.:0.0   1st Qu.:40.48   1st Qu.:-3.450   1st Qu.:263.0  
 Median :2.00   Median :0.5   Median :41.08   Median :-2.242   Median :435.6  
 Mean   :1.80   Mean   :1.1   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:2.00   3rd Qu.:1.0   3rd Qu.:41.67   3rd Qu.:-1.033   3rd Qu.:608.1  
 Max.   :3.00   Max.   :7.0   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax             tmin            precip      
 Min.   : 1.000   Min.   :-12.00   Min.   :-72.00   Min.   :  5.00  
 1st Qu.: 1.000   1st Qu.: 12.75   1st Qu.:-40.75   1st Qu.: 30.75  
 Median : 2.000   Median : 27.00   Median :-26.50   Median : 49.50  
 Mean   : 3.062   Mean   : 30.47   Mean   :-26.97   Mean   : 50.75  
 3rd Qu.: 3.000   3rd Qu.: 46.00   3rd Qu.:-16.50   3rd Qu.: 68.50  
 Max.   :12.000   Max.   : 99.00   Max.   : 28.00   Max.   :180.00  
     nevada    prof_nieve       longitud        latitud         altitud    
 Min.   :0   Min.   :175.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:0   1st Qu.:218.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :0   Median :280.5   Median :40.78   Median :-4.01   Median :1894  
 Mean   :0   Mean   :339.0   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:0   3rd Qu.:438.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :0   Max.   :709.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax          tmin             precip           nevada 
 Min.   : 1.000   Min.   :-53   Min.   :-121.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.:146   1st Qu.:  50.00   1st Qu.:  3.00   1st Qu.:0  
 Median : 6.000   Median :194   Median :  93.00   Median : 11.00   Median :0  
 Mean   : 6.499   Mean   :199   Mean   :  94.93   Mean   : 16.95   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:255   3rd Qu.: 141.00   3rd Qu.: 23.00   3rd Qu.:0  
 Max.   :12.000   Max.   :403   Max.   : 254.00   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:38.99   1st Qu.: -4.8500   1st Qu.:  44.0  
 Median :  0.0000   Median :40.96   Median : -2.4831   Median : 251.0  
 Mean   :  0.1514   Mean   :40.54   Mean   : -2.4502   Mean   : 409.5  
 3rd Qu.:  0.0000   3rd Qu.:42.23   3rd Qu.:  0.4942   3rd Qu.: 667.0  
 Max.   :165.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.:201.0   1st Qu.:132.0   1st Qu.:  0.00   1st Qu.:0  
 Median : 7.000   Median :225.0   Median :160.0   Median :  1.00   Median :0  
 Mean   : 6.503   Mean   :217.5   Mean   :150.7   Mean   :  6.86   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:253.0   3rd Qu.:190.0   3rd Qu.:  8.00   3rd Qu.:0  
 Max.   :12.000   Max.   :356.0   Max.   :244.0   Max.   :114.00   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.: 0.00000   1st Qu.:28.31   1st Qu.:-16.56   1st Qu.:  25.0  
 Median : 0.00000   Median :28.44   Median :-16.33   Median :  35.0  
 Mean   : 0.03089   Mean   :28.36   Mean   :-16.05   Mean   : 518.5  
 3rd Qu.: 0.00000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 632.0  
 Max.   :46.00000   Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt         tmax             tmin            precip     
 Min.   : 1.0   Min.   : 69.00   Min.   :-24.00   Min.   : 3.00  
 1st Qu.: 2.0   1st Qu.: 86.25   1st Qu.:-12.50   1st Qu.: 6.00  
 Median : 7.0   Median : 92.00   Median :  6.50   Median :10.50  
 Mean   : 6.8   Mean   : 96.80   Mean   :  7.90   Mean   :11.40  
 3rd Qu.:12.0   3rd Qu.: 96.75   3rd Qu.: 29.25   3rd Qu.:14.75  
 Max.   :12.0   Max.   :140.00   Max.   : 35.00   Max.   :24.00  
     nevada       prof_nieve     longitud        latitud          altitud     
 Min.   :1.00   Min.   :0.0   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.:1.25   1st Qu.:0.0   1st Qu.:40.48   1st Qu.:-3.450   1st Qu.:263.0  
 Median :2.00   Median :0.5   Median :41.08   Median :-2.242   Median :435.6  
 Mean   :1.80   Mean   :1.1   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:2.00   3rd Qu.:1.0   3rd Qu.:41.67   3rd Qu.:-1.033   3rd Qu.:608.1  
 Max.   :3.00   Max.   :7.0   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax             tmin            precip      
 Min.   : 1.000   Min.   :-12.00   Min.   :-72.00   Min.   :  5.00  
 1st Qu.: 1.000   1st Qu.: 12.75   1st Qu.:-40.75   1st Qu.: 30.75  
 Median : 2.000   Median : 27.00   Median :-26.50   Median : 49.50  
 Mean   : 3.062   Mean   : 30.47   Mean   :-26.97   Mean   : 50.75  
 3rd Qu.: 3.000   3rd Qu.: 46.00   3rd Qu.:-16.50   3rd Qu.: 68.50  
 Max.   :12.000   Max.   : 99.00   Max.   : 28.00   Max.   :180.00  
     nevada    prof_nieve       longitud        latitud         altitud    
 Min.   :0   Min.   :175.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:0   1st Qu.:218.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :0   Median :280.5   Median :40.78   Median :-4.01   Median :1894  
 Mean   :0   Mean   :339.0   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:0   3rd Qu.:438.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :0   Max.   :709.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.:127.0   1st Qu.:  32.00   1st Qu.:  6.00  
 Median : 5.000   Median :161.0   Median :  64.00   Median : 16.00  
 Mean   : 6.031   Mean   :159.4   Mean   :  65.05   Mean   : 20.81  
 3rd Qu.:10.000   3rd Qu.:192.0   3rd Qu.:  96.00   3rd Qu.: 30.00  
 Max.   :12.000   Max.   :352.0   Max.   : 221.00   Max.   :126.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :  0.0000   Min.   :28.48   Min.   :-16.3292  
 1st Qu.:0   1st Qu.:  0.0000   1st Qu.:39.56   1st Qu.: -5.6000  
 Median :0   Median :  0.0000   Median :41.42   Median : -2.9553  
 Mean   :0   Mean   :  0.2245   Mean   :40.89   Mean   : -2.6932  
 3rd Qu.:0   3rd Qu.:  0.0000   3rd Qu.:42.52   3rd Qu.:  0.4914  
 Max.   :0   Max.   :165.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.:  47.0  
 Median : 251.0  
 Mean   : 425.9  
 3rd Qu.: 667.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   :100.0   Min.   :0  
 1st Qu.: 3.000   1st Qu.:119.0   1st Qu.: 57.00   1st Qu.:110.0   1st Qu.:0  
 Median :10.000   Median :140.0   Median : 78.00   Median :121.0   Median :0  
 Mean   : 7.533   Mean   :146.3   Mean   : 79.49   Mean   :132.5   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:170.0   3rd Qu.:102.00   3rd Qu.:141.8   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud       
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.00  
 1st Qu.:  0.0000   1st Qu.:41.29   1st Qu.: -8.616   1st Qu.:  36.75  
 Median :  0.0000   Median :42.43   Median : -7.860   Median : 256.00  
 Mean   :  0.6936   Mean   :41.34   Mean   : -5.770   Mean   : 340.98  
 3rd Qu.:  0.0000   3rd Qu.:42.89   3rd Qu.: -2.039   3rd Qu.: 370.00  
 Max.   :123.0000   Max.   :43.57   Max.   :  3.035   Max.   :2400.00  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.:201.0   1st Qu.:132.0   1st Qu.:  0.00   1st Qu.:0  
 Median : 7.000   Median :225.0   Median :160.0   Median :  1.00   Median :0  
 Mean   : 6.503   Mean   :217.5   Mean   :150.7   Mean   :  6.86   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:253.0   3rd Qu.:190.0   3rd Qu.:  8.00   3rd Qu.:0  
 Max.   :12.000   Max.   :356.0   Max.   :244.0   Max.   :114.00   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.89   Min.   :  14.0  
 1st Qu.: 0.00000   1st Qu.:28.31   1st Qu.:-16.56   1st Qu.:  25.0  
 Median : 0.00000   Median :28.44   Median :-16.33   Median :  35.0  
 Mean   : 0.03089   Mean   :28.36   Mean   :-16.05   Mean   : 518.5  
 3rd Qu.: 0.00000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 632.0  
 Max.   :46.00000   Max.   :28.95   Max.   :-13.60   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   :163.0   Min.   : 42.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 6.000   1st Qu.:245.0   1st Qu.:122.0   1st Qu.: 1.000   1st Qu.:0  
 Median : 7.000   Median :275.0   Median :152.0   Median : 5.000   Median :0  
 Mean   : 7.361   Mean   :274.8   Mean   :151.6   Mean   : 7.276   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:303.0   3rd Qu.:181.0   3rd Qu.:12.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :44.000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :35.28   Min.   :-8.6239   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:38.28   1st Qu.:-4.1153   1st Qu.:  43.0  
 Median : 0.00000   Median :40.41   Median :-1.8631   Median : 247.0  
 Mean   : 0.00245   Mean   :39.88   Mean   :-1.9231   Mean   : 380.1  
 3rd Qu.: 0.00000   3rd Qu.:41.52   3rd Qu.: 0.5706   3rd Qu.: 667.0  
 Max.   :35.00000   Max.   :43.36   Max.   : 4.2156   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt         tmax             tmin            precip     
 Min.   : 1.0   Min.   : 69.00   Min.   :-24.00   Min.   : 3.00  
 1st Qu.: 2.0   1st Qu.: 86.25   1st Qu.:-12.50   1st Qu.: 6.00  
 Median : 7.0   Median : 92.00   Median :  6.50   Median :10.50  
 Mean   : 6.8   Mean   : 96.80   Mean   :  7.90   Mean   :11.40  
 3rd Qu.:12.0   3rd Qu.: 96.75   3rd Qu.: 29.25   3rd Qu.:14.75  
 Max.   :12.0   Max.   :140.00   Max.   : 35.00   Max.   :24.00  
     nevada       prof_nieve     longitud        latitud          altitud     
 Min.   :1.00   Min.   :0.0   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.:1.25   1st Qu.:0.0   1st Qu.:40.48   1st Qu.:-3.450   1st Qu.:263.0  
 Median :2.00   Median :0.5   Median :41.08   Median :-2.242   Median :435.6  
 Mean   :1.80   Mean   :1.1   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:2.00   3rd Qu.:1.0   3rd Qu.:41.67   3rd Qu.:-1.033   3rd Qu.:608.1  
 Max.   :3.00   Max.   :7.0   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax             tmin            precip      
 Min.   : 1.000   Min.   :-12.00   Min.   :-72.00   Min.   :  5.00  
 1st Qu.: 1.000   1st Qu.: 12.75   1st Qu.:-40.75   1st Qu.: 30.75  
 Median : 2.000   Median : 27.00   Median :-26.50   Median : 49.50  
 Mean   : 3.062   Mean   : 30.47   Mean   :-26.97   Mean   : 50.75  
 3rd Qu.: 3.000   3rd Qu.: 46.00   3rd Qu.:-16.50   3rd Qu.: 68.50  
 Max.   :12.000   Max.   : 99.00   Max.   : 28.00   Max.   :180.00  
     nevada    prof_nieve       longitud        latitud         altitud    
 Min.   :0   Min.   :175.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:0   1st Qu.:218.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :0   Median :280.5   Median :40.78   Median :-4.01   Median :1894  
 Mean   :0   Mean   :339.0   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:0   3rd Qu.:438.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :0   Max.   :709.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : -4.0   Min.   :-110.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:131.0   1st Qu.:  35.0   1st Qu.:  6.00   1st Qu.:0  
 Median : 4.000   Median :164.0   Median :  66.0   Median : 15.00   Median :0  
 Mean   : 6.009   Mean   :163.2   Mean   :  67.7   Mean   : 20.17   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:194.0   3rd Qu.:  98.0   3rd Qu.: 29.00   3rd Qu.:0  
 Max.   :12.000   Max.   :352.0   Max.   : 221.0   Max.   :104.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :28.48   Min.   :-16.3292   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:39.49   1st Qu.: -5.6156   1st Qu.:  44.0  
 Median : 0.00000   Median :41.38   Median : -3.1742   Median : 240.0  
 Mean   : 0.07386   Mean   :40.83   Mean   : -2.8205   Mean   : 347.5  
 3rd Qu.: 0.00000   3rd Qu.:42.45   3rd Qu.:  0.3664   3rd Qu.: 617.0  
 Max.   :75.00000   Max.   :43.57   Max.   :  4.2156   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin            precip          nevada 
 Min.   : 1.000   Min.   : -8.0   Min.   :-58.00   Min.   :100.0   Min.   :0  
 1st Qu.: 3.000   1st Qu.:119.0   1st Qu.: 57.00   1st Qu.:110.0   1st Qu.:0  
 Median :10.000   Median :140.0   Median : 78.00   Median :121.0   Median :0  
 Mean   : 7.533   Mean   :146.3   Mean   : 79.49   Mean   :132.5   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:170.0   3rd Qu.:102.00   3rd Qu.:141.8   3rd Qu.:0  
 Max.   :12.000   Max.   :350.0   Max.   :223.00   Max.   :422.0   Max.   :0  
   prof_nieve          longitud        latitud           altitud       
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.00  
 1st Qu.:  0.0000   1st Qu.:41.29   1st Qu.: -8.616   1st Qu.:  36.75  
 Median :  0.0000   Median :42.43   Median : -7.860   Median : 256.00  
 Mean   :  0.6936   Mean   :41.34   Mean   : -5.770   Mean   : 340.98  
 3rd Qu.:  0.0000   3rd Qu.:42.89   3rd Qu.: -2.039   3rd Qu.: 370.00  
 Max.   :123.0000   Max.   :43.57   Max.   :  3.035   Max.   :2400.00  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax          tmin           precip            nevada 
 Min.   : 1.000   Min.   : 87   Min.   : 64.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 3.000   1st Qu.:212   1st Qu.:150.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 6.000   Median :233   Median :168.0   Median :  1.000   Median :0  
 Mean   : 6.486   Mean   :234   Mean   :169.5   Mean   :  6.141   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:259   3rd Qu.:196.0   3rd Qu.:  7.000   3rd Qu.:0  
 Max.   :12.000   Max.   :356   Max.   :244.0   Max.   :103.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud     
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.89   Min.   : 14.0  
 1st Qu.:0.0000000   1st Qu.:28.05   1st Qu.:-16.56   1st Qu.: 25.0  
 Median :0.0000000   Median :28.46   Median :-16.26   Median : 33.0  
 Mean   :0.0003525   Mean   :28.38   Mean   :-15.95   Mean   :130.3  
 3rd Qu.:0.0000000   3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.: 64.0  
 Max.   :2.0000000   Max.   :28.95   Max.   :-13.60   Max.   :632.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax             tmin              precip      
 Min.   : 1.000   Min.   :-53.00   Min.   :-121.000   Min.   :  0.00  
 1st Qu.: 3.000   1st Qu.: 29.00   1st Qu.: -34.000   1st Qu.: 19.00  
 Median : 6.000   Median : 69.00   Median :   3.000   Median : 31.00  
 Mean   : 6.507   Mean   : 74.65   Mean   :   6.685   Mean   : 34.99  
 3rd Qu.:10.000   3rd Qu.:119.00   3rd Qu.:  47.250   3rd Qu.: 47.00  
 Max.   :12.000   Max.   :218.00   Max.   : 128.000   Max.   :126.00  
     nevada    prof_nieve         longitud        latitud           altitud    
 Min.   :0   Min.   :  0.000   Min.   :40.78   Min.   :-4.0103   Min.   :1405  
 1st Qu.:0   1st Qu.:  0.000   1st Qu.:41.77   1st Qu.: 0.7292   1st Qu.:1894  
 Median :0   Median :  0.000   Median :42.47   Median : 0.9844   Median :2230  
 Mean   :0   Mean   :  3.539   Mean   :42.06   Mean   : 0.1067   Mean   :2150  
 3rd Qu.:0   3rd Qu.:  0.000   3rd Qu.:42.64   3rd Qu.: 1.5242   3rd Qu.:2400  
 Max.   :0   Max.   :165.000   Max.   :42.77   Max.   : 2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   :163.0   Min.   : 42.0   Min.   : 0.000   Min.   :0  
 1st Qu.: 6.000   1st Qu.:245.0   1st Qu.:122.0   1st Qu.: 1.000   1st Qu.:0  
 Median : 7.000   Median :275.0   Median :152.0   Median : 5.000   Median :0  
 Mean   : 7.361   Mean   :274.8   Mean   :151.6   Mean   : 7.276   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:303.0   3rd Qu.:181.0   3rd Qu.:12.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254.0   Max.   :44.000   Max.   :0  
   prof_nieve          longitud        latitud           altitud      
 Min.   : 0.00000   Min.   :35.28   Min.   :-8.6239   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:38.28   1st Qu.:-4.1153   1st Qu.:  43.0  
 Median : 0.00000   Median :40.41   Median :-1.8631   Median : 247.0  
 Mean   : 0.00245   Mean   :39.88   Mean   :-1.9231   Mean   : 380.1  
 3rd Qu.: 0.00000   3rd Qu.:41.52   3rd Qu.: 0.5706   3rd Qu.: 667.0  
 Max.   :35.00000   Max.   :43.36   Max.   : 4.2156   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt      tmax            tmin        precip          nevada   
 Min.   :2   Min.   :71.00   Min.   :-1   Min.   :14.00   Min.   :4.0  
 1st Qu.:2   1st Qu.:72.25   1st Qu.:-1   1st Qu.:15.25   1st Qu.:4.5  
 Median :2   Median :73.50   Median :-1   Median :16.50   Median :5.0  
 Mean   :2   Mean   :73.50   Mean   :-1   Mean   :16.50   Mean   :5.0  
 3rd Qu.:2   3rd Qu.:74.75   3rd Qu.:-1   3rd Qu.:17.75   3rd Qu.:5.5  
 Max.   :2   Max.   :76.00   Max.   :-1   Max.   :19.00   Max.   :6.0  
   prof_nieve    longitud        latitud          altitud     
 Min.   : 5   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.: 7   1st Qu.:40.78   1st Qu.:-2.846   1st Qu.:349.3  
 Median : 9   Median :41.08   Median :-2.242   Median :435.6  
 Mean   : 9   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:11   3rd Qu.:41.37   3rd Qu.:-1.637   3rd Qu.:521.8  
 Max.   :13   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt         tmax             tmin            precip     
 Min.   : 1.0   Min.   : 69.00   Min.   :-24.00   Min.   : 3.00  
 1st Qu.: 2.0   1st Qu.: 86.25   1st Qu.:-12.50   1st Qu.: 6.00  
 Median : 7.0   Median : 92.00   Median :  6.50   Median :10.50  
 Mean   : 6.8   Mean   : 96.80   Mean   :  7.90   Mean   :11.40  
 3rd Qu.:12.0   3rd Qu.: 96.75   3rd Qu.: 29.25   3rd Qu.:14.75  
 Max.   :12.0   Max.   :140.00   Max.   : 35.00   Max.   :24.00  
     nevada       prof_nieve     longitud        latitud          altitud     
 Min.   :1.00   Min.   :0.0   Min.   :40.48   Min.   :-3.450   Min.   :263.0  
 1st Qu.:1.25   1st Qu.:0.0   1st Qu.:40.48   1st Qu.:-3.450   1st Qu.:263.0  
 Median :2.00   Median :0.5   Median :41.08   Median :-2.242   Median :435.6  
 Mean   :1.80   Mean   :1.1   Mean   :41.08   Mean   :-2.242   Mean   :435.6  
 3rd Qu.:2.00   3rd Qu.:1.0   3rd Qu.:41.67   3rd Qu.:-1.033   3rd Qu.:608.1  
 Max.   :3.00   Max.   :7.0   Max.   :41.67   Max.   :-1.033   Max.   :608.1  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax             tmin            precip      
 Min.   : 1.000   Min.   :-12.00   Min.   :-72.00   Min.   :  5.00  
 1st Qu.: 1.000   1st Qu.: 12.75   1st Qu.:-40.75   1st Qu.: 30.75  
 Median : 2.000   Median : 27.00   Median :-26.50   Median : 49.50  
 Mean   : 3.062   Mean   : 30.47   Mean   :-26.97   Mean   : 50.75  
 3rd Qu.: 3.000   3rd Qu.: 46.00   3rd Qu.:-16.50   3rd Qu.: 68.50  
 Max.   :12.000   Max.   : 99.00   Max.   : 28.00   Max.   :180.00  
     nevada    prof_nieve       longitud        latitud         altitud    
 Min.   :0   Min.   :175.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.:0   1st Qu.:218.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :0   Median :280.5   Median :40.78   Median :-4.01   Median :1894  
 Mean   :0   Mean   :339.0   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:0   3rd Qu.:438.0   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :0   Max.   :709.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :1.000   Min.   :-4.00   Min.   :-51.00   Min.   : 19.00   Min.   :0  
 1st Qu.:2.000   1st Qu.: 4.50   1st Qu.:-43.50   1st Qu.: 45.00   1st Qu.:0  
 Median :2.500   Median :21.00   Median :-30.00   Median : 50.00   Median :0  
 Mean   :2.375   Mean   :18.88   Mean   :-33.00   Mean   : 58.25   Mean   :0  
 3rd Qu.:3.000   3rd Qu.:35.25   3rd Qu.:-23.75   3rd Qu.: 63.75   3rd Qu.:0  
 Max.   :3.000   Max.   :36.00   Max.   :-16.00   Max.   :122.00   Max.   :0  
   prof_nieve        longitud        latitud         altitud    
 Min.   : 784.0   Min.   :40.78   Min.   :-4.01   Min.   :1894  
 1st Qu.: 865.8   1st Qu.:40.78   1st Qu.:-4.01   1st Qu.:1894  
 Median :1045.0   Median :40.78   Median :-4.01   Median :1894  
 Mean   :1131.1   Mean   :40.78   Mean   :-4.01   Mean   :1894  
 3rd Qu.:1249.5   3rd Qu.:40.78   3rd Qu.:-4.01   3rd Qu.:1894  
 Max.   :1834.0   Max.   :40.78   Max.   :-4.01   Max.   :1894  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 13.0   Min.   :-33.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.: 94.0   1st Qu.: 23.00   1st Qu.:  0.00   1st Qu.:0  
 Median : 7.000   Median :129.0   Median : 51.00   Median :  3.00   Median :0  
 Mean   : 6.585   Mean   :138.4   Mean   : 60.83   Mean   : 10.29   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:183.0   3rd Qu.: 98.00   3rd Qu.: 13.00   3rd Qu.:0  
 Max.   :12.000   Max.   :253.0   Max.   :159.00   Max.   :114.00   Max.   :0  
   prof_nieve         longitud        latitud         altitud    
 Min.   : 0.0000   Min.   :28.31   Min.   :-16.5   Min.   :2371  
 1st Qu.: 0.0000   1st Qu.:28.31   1st Qu.:-16.5   1st Qu.:2371  
 Median : 0.0000   Median :28.31   Median :-16.5   Median :2371  
 Mean   : 0.1766   Mean   :28.31   Mean   :-16.5   Mean   :2371  
 3rd Qu.: 0.0000   3rd Qu.:28.31   3rd Qu.:-16.5   3rd Qu.:2371  
 Max.   :46.0000   Max.   :28.31   Max.   :-16.5   Max.   :2371  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBtZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiAyODkKKiBEZXNjcmlwY2nDs246IAoqIEZyZWN1ZW5jaWE6IG1lcwoqIFZhcmlhYmxlczogdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkCiogRGltZW5zaW9uZXMgZGVsIG1hcGE6IDUsNQoqIEl0ZXJhY2lvbmVzOiAxMDAwCiogUGFyw6FtZXRyb3MgYWRpY2lvbmFsZXM6IAoKYGBge3J9CnNvdXJjZSgiLi4vLi4vbGliL3NvbS11dGlscy5SIikKc291cmNlKCIuLi8uLi9saWIvbWFwcy11dGlscy5SIikKYGBgCgojIENhcmdhIGRlbCBtb2RlbG8gZGVzZGUgZGlzY28KCmBgYHtyfQptcHIuc2V0X2Jhc2VfcGF0aF9hbmFseXNpcygpCm1vZGVsIDwtIG1wci5sb2FkX21vZGVsKCJzb20tMjg5LnJkcy54eiIpCnN1bW1hcnkobW9kZWwpCmBgYAoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImNoYW5nZXMiKQpgYGAKCiMgQ2FyZ2EgZGVsIGRhdGFzZXQgZGUgZW50cmFkYQoKYGBge3J9CmRmIDwtIG1wci5sb2FkX2RhdGEoImRhdG9zX21lcy5jc3YueHoiKQpgYGAKCmBgYHtyfQpkZgpgYGAKCmBgYHtyfQpzdW1tYXJ5KGRmKQpgYGAKCiMgQ2FyZ2EgZGUgbG9zIG1hcGFzCgpgYGB7cn0Kd29ybGQgPC0gbmVfY291bnRyaWVzKHNjYWxlID0gIm1lZGl1bSIsIHJldHVybmNsYXNzID0gInNmIikKc3BhaW4gPC0gc3Vic2V0KHdvcmxkLCBhZG1pbiA9PSAiU3BhaW4iKQpgYGAKCiMgTWFwYSBkZSBkZW5zaWRhZAoKYGBge3J9CnBsb3QobW9kZWwsIHR5cGU9ImNvdW50Iiwgc2hhcGUgPSAic3RyYWlnaHQiLCBwYWxldHRlLm5hbWUgPSBtcHIuZGVncmFkZS5ibGV1KQpgYGAKCk7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2VsZGE6CgpgYGB7cn0KbmIgPC0gdGFibGUobW9kZWwkdW5pdC5jbGFzc2lmKQpwcmludChuYikKYGBgCkNvbXByb2JhY2nDs24gZGUgbm9kb3MgdmFjw61vczoKCmBgYHtyfQpkaW1fbW9kZWwgPC0gNSo1OwpsZW5fbmIgPSBsZW5ndGgobmIpOwplbXB0eV9ub2RlcyA8LSBkaW1fbW9kZWwgIT0gbGVuX25iOwppZiAoZW1wdHlfbm9kZXMpIHsKICBwcmludChwYXN0ZSgiW1dhcm5pbmddIEV4aXN0ZW4gbm9kb3MgdmFjw61vczogIiwgbGVuX25iLCAiLyIsIGRpbV9tb2RlbCkpCn0KYGBgCgojIE1hcGEgZGUgZGlzdGFuY2lhIGVudHJlIHZlY2lub3MKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJkaXN0Lm5laWdoYm91cnMiLCBzaGFwZSA9ICJzdHJhaWdodCIpCmBgYAoKIyBJbmZsdWVuY2lhIGRlIGxhcyB2YXJpYWJsZXMKCmBgYHtyfQptb2RlbF9jb2xuYW1lcyA9IGMoInRtYXgiLCAidG1pbiIsICJwcmVjaXAiLCAibmV2YWRhIiwgInByb2ZfbmlldmUiLCAibG9uZ2l0dWQiLCAibGF0aXR1ZCIsICJhbHRpdHVkIikKbW9kZWxfbmNvbCA9IGxlbmd0aChtb2RlbF9jb2xuYW1lcykKYGBgCgojIyBNYXBhIGRlIHZhcmlhYmxlcy4KCmBgYHtyfQpwbG90KG1vZGVsLCBzaGFwZSA9ICJzdHJhaWdodCIpCmBgYAoKIyMgTWFwYSBkZSBjYWxvciBwb3IgdmFyaWFibGUKCmBgYHtyfQpwYXIobWZyb3c9YygzLDQpKQpmb3IgKGogaW4gMTptb2RlbF9uY29sKSB7CiAgcGxvdChtb2RlbCwgdHlwZT0icHJvcGVydHkiLCBwcm9wZXJ0eT1nZXRDb2Rlcyhtb2RlbCwxKVssal0sCiAgICBwYWxldHRlLm5hbWU9bXByLmNvb2xCbHVlSG90UmVkLAogICAgbWFpbj1tb2RlbF9jb2xuYW1lc1tqXSwKICAgIGNleD0wLjUsIHNoYXBlID0gInN0cmFpZ2h0IikKfQpgYGAKCiMjIENvcnJlbGFjacOzbiBwYXJhIGNhZGEgY29sdW1uYSBkZWwgdmVjdG9yIGRlIG5vZG9zCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGNvciA8LSBhcHBseShnZXRDb2Rlcyhtb2RlbCwxKSwgMiwgbXByLndlaWdodGVkLmNvcnJlbGF0aW9uLCB3PW5iLCBzb209bW9kZWwpCiAgcHJpbnQoY29yKQp9CmBgYAoKUmVwcmVzZW50YWNpw7NuIGRlIGNhZGEgdmFyaWFibGUgZW4gdW4gbWFwYSBkZSBmYWN0b3JlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGFyKG1mcm93PWMoMSwxKSkKICBwbG90KGNvclsxLF0sIGNvclsyLF0sIHhsaW09YygtMSwxKSwgeWxpbT1jKC0xLDEpLCB0eXBlPSJuIikKICBsaW5lcyhjKC0xLDEpLGMoMCwwKSkKICBsaW5lcyhjKDAsMCksYygtMSwxKSkKICB0ZXh0KGNvclsxLF0sIGNvclsyLF0sIGxhYmVscz1tb2RlbF9jb2xuYW1lcywgY2V4PTAuNzUpCiAgc3ltYm9scygwLDAsY2lyY2xlcz0xLGluY2hlcz1GLGFkZD1UKQp9CmBgYAoKSW1wb3J0YW5jaWEgZGUgY2FkYSB2YXJpYWJsZSAtIHZhcmlhbnphIHBvbmRlcmFkYSBwb3IgZWwgdGFtYcOxbyBkZSBsYSBjZWxkYToKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgc2lnbWEyIDwtIHNxcnQoYXBwbHkoZ2V0Q29kZXMobW9kZWwsMSksMixmdW5jdGlvbih4LGVmZmVjdGlmKQogICAgIHttPC1zdW0oZWZmZWN0aWYqKHgtd2VpZ2h0ZWQubWVhbih4LGVmZmVjdGlmKSleMikvKHN1bShlZmZlY3RpZiktMSl9LAogICAgIGVmZmVjdGlmPW5iKSkKICBwcmludChzb3J0KHNpZ21hMixkZWNyZWFzaW5nPVQpKQp9CmBgYAoKIyBDbHVzdGVyaW5nCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGhhYyA8LSBtcHIuaGFjKG1vZGVsLCBuYikKfQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDMgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz0zKQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9MykKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA0IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9NCkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTQpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDUgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz01KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NSkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDYgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz02KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NikKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSwgZGltKGRmLmNsdXN0ZXIwNilbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCiAgZGYuY2x1c3RlcjA2Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDYpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDYuZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSA4IGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9OCkKfQpgYGAKCiMjIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgY2zDunN0ZXJzIGVuIGVsIG1hcGEKCkEgcXXDqSBjbMO6c3RlciBwZXJ0ZW5lY2UgY2FkYSBub2RvIGRlbCBtYXBhIGRlIGtvaG9uZW46CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGdyb3VwcyA8LSBjdXRyZWUoaGFjLCBrPTgpCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCiAgZGYuY2x1c3RlcjA2IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NikKICBkZi5jbHVzdGVyMDcgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT03KQogIGRmLmNsdXN0ZXIwOCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTgpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA3IDwtIHNlbGVjdChkZi5jbHVzdGVyMDcsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwOCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA4LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDgpCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSwgZGltKGRmLmNsdXN0ZXIwNilbMV0sIGRpbShkZi5jbHVzdGVyMDcpWzFdLCBkaW0oZGYuY2x1c3RlcjA4KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiwgImNsdXN0ZXIwNyIsICJjbHVzdGVyMDgiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDgpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOCkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCiAgZGYuY2x1c3RlcjA2Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDYpCiAgZGYuY2x1c3RlcjA3Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDcpCiAgZGYuY2x1c3RlcjA4Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDgpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDYuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDcuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDguZ3JvdXBlZCkKYGBgCgojIyBWaXN1YWxpemFjacOzbiBkZSAxMCBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTEwKQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9MTApCiAgcGxvdChtb2RlbCwgdHlwZT0ibWFwcGluZyIsCiAgICBiZ2NvbD1jKCJzdGVlbGJsdWUxIiwic2llbm5hMSIsInllbGxvd2dyZWVuIiwicmVkIiwiYmx1ZSIsInllbGxvdyIsInB1cnBsZSIsImdyZWVuIiwid2hpdGUiLCIjMWY3N2I0IiwgJyNmZjdmMGUnLCAnIzJjYTAyYycsICcjZDYyNzI4JywgJyM5NDY3YmQnLCAnIzhjNTY0YicsICcjZTM3N2MyJylbZ3JvdXBzXSwKICAgIHNoYXBlID0gInN0cmFpZ2h0IiwgbGFiZWxzID0gIiIpCiAgYWRkLmNsdXN0ZXIuYm91bmRhcmllcyhtb2RlbCwgY2x1c3RlcmluZz1ncm91cHMpCn0KYGBgCgojIyMgQW7DoWxpc2lzIGRlIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIEFzaWduYW1vcyBhIGNhZGEgcmVnaXN0cm8gc3UgY2zDunN0ZXIKICBkZiRjbHVzdGVyIDwtIGdyb3Vwc1ttb2RlbCR1bml0LmNsYXNzaWZdCn0KYGBgCgpOdWV2b3MgZGF0YWZyYW1lcyBwb3IgY2x1c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICAjIENyZW8gbnVldm9zIGRhdGFmcmFtZXMsIHVubyBwb3IgY2FkYSBjbMO6c3Rlci4KICBkZi5jbHVzdGVyMDEgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xKQogIGRmLmNsdXN0ZXIwMiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTIpCiAgZGYuY2x1c3RlcjAzIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MykKICBkZi5jbHVzdGVyMDQgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT00KQogIGRmLmNsdXN0ZXIwNSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTUpCiAgZGYuY2x1c3RlcjA2IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NikKICBkZi5jbHVzdGVyMDcgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT03KQogIGRmLmNsdXN0ZXIwOCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTgpCiAgZGYuY2x1c3RlcjA5IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OSkKICBkZi5jbHVzdGVyMTAgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0xMCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDcgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA4IDwtIHNlbGVjdChkZi5jbHVzdGVyMDgsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwOSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA5LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMTAgPC0gc2VsZWN0KGRmLmNsdXN0ZXIxMCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA4KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMTApCmBgYAoKIyMjIyBOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNsw7pzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXJzLmRpbSA8LSBjKGRpbShkZi5jbHVzdGVyMDEpWzFdLCBkaW0oZGYuY2x1c3RlcjAyKVsxXSwgZGltKGRmLmNsdXN0ZXIwMylbMV0sIGRpbShkZi5jbHVzdGVyMDQpWzFdLCBkaW0oZGYuY2x1c3RlcjA1KVsxXSwgZGltKGRmLmNsdXN0ZXIwNilbMV0sIGRpbShkZi5jbHVzdGVyMDcpWzFdLCBkaW0oZGYuY2x1c3RlcjA4KVsxXSwgZGltKGRmLmNsdXN0ZXIwOSlbMV0sIGRpbShkZi5jbHVzdGVyMTApWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiLCAiY2x1c3RlcjA3IiwgImNsdXN0ZXIwOCIsICJjbHVzdGVyMDkiLCAiY2x1c3RlcjEwIiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA4KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDkpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIxMCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA4KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDkpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIxMCkKYGBgCgojIyMgTG9jYWxpemFjacOzbiBnZW9ncsOhZmljYSBkZSBsYXMgZXN0YWNpb25lcyBkZSBtZWRpZGEgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KIyBBZ3J1cGEgcG9yIGxvbmdpdHVkIHkgbGF0aXR1ZCBwYXJhIHJlbGxlbmFyIGVsIG1hcGEgY29uIG1lbm9zIGRhdG9zLgppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcjAxLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDEpCiAgZGYuY2x1c3RlcjAyLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDIpCiAgZGYuY2x1c3RlcjAzLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDMpCiAgZGYuY2x1c3RlcjA0Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDQpCiAgZGYuY2x1c3RlcjA1Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDUpCiAgZGYuY2x1c3RlcjA2Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDYpCiAgZGYuY2x1c3RlcjA3Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDcpCiAgZGYuY2x1c3RlcjA4Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDgpCiAgZGYuY2x1c3RlcjA5Lmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMDkpCiAgZGYuY2x1c3RlcjEwLmdyb3VwZWQgPC0gbXByLmdyb3VwX2J5X2dlbyhkZi5jbHVzdGVyMTApCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDEuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDIuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDMuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDQuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDUuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDYuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDcuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDguZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMDkuZ3JvdXBlZCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmRyYXdfbWFwKHNwYWluLCBkZi5jbHVzdGVyMTAuZ3JvdXBlZCkKYGBgCg==